import {
  Paragraph,
  TextRun,
  ParagraphChild,
  ImageRun,
  Table,
  TableRow,
  TableCell,
  TableLayoutType,
  WidthType
} from 'docx'

import {
  cssStylesToAttrs,
  tagsToAttrs,
  getInlineStyles,
  getTableCellAttrs
} from './style'
import { cloneDeep } from 'lodash-es'
import { pxToPt } from '../utils'

export function richTextToParagraph(richText: string | string[]) {
  const paragraphNodes: (Paragraph | Table)[] = []

  const richTextArr = Array.isArray(richText) ? richText : [richText]

  richTextArr.forEach((rich) => {
    paragraphNodes.push(
      new Paragraph({
        pageBreakBefore: true
      })
    )
    paragraphNodes.push(...convertRichTextToParagraphNodes(rich))
  })
  return paragraphNodes
}

/**
 * @see https://docx.js.org/
 */
function convertRichTextToParagraphNodes(richText: string) {
  const container = document.createElement('div')
  container.innerHTML = richText
  const parsedHtml = new DOMParser().parseFromString(richText, 'text/html')

  const paragraphNodes: (Paragraph | Table)[] = []

  /**
   * 默认值需要在最后面判定，因为自定义合并判定子集样式优先
   * 自定义合并优先 target 值 其次是 source
   */
  const defaultNodeAttrs = cssStylesToAttrs({
    fontFamily: '方正仿宋_GBK',
    fontSize: '12pt'
  })

  /**
   * 只查询平级正文标签
   * .main-body > .reedit-wrapper p 作为兼容项
   */
  const selectors = [
    'p',
    'h1',
    'h2',
    'h3',
    'h4',
    'h5',
    'h6',
    'table',
    '.main-body > .reedit-wrapper p'
  ]

  const elementNodes = parsedHtml.body.querySelectorAll(
    ':scope > ' + selectors.join(',')
  )

  elementNodes.forEach((element) => {
    const paragraphChildrenNodes: ParagraphChild[] = []

    const rootStyles = cssStylesToAttrs(getInlineStyles(element))

    const rootTagName = element.tagName.toLocaleLowerCase()

    if (rootTagName === 'table') {
      const rows = element.querySelectorAll('tr')
      const tableRowNodes: TableRow[] = []

      rows.forEach((row) => {
        const cells: TableCell[] = []

        Array.from(row.children).forEach((cell) => {
          const cellParagraphChildrenNodes: ParagraphChild[] = []

          recursionDeep(
            Array.from(cell.childNodes),
            rootStyles,
            cellParagraphChildrenNodes
          )

          const paragraph = new Paragraph({
            children: cellParagraphChildrenNodes,
            spacing: {
              line: rootStyles.lineSpacing,
              lineRule: 'exact'
            },
            alignment: rootStyles.alignment,
            indent: rootStyles.indent
          })

          cells.push(
            new TableCell({
              ...getTableCellAttrs(cell),
              children: [paragraph]
            })
          )
        })
        tableRowNodes.push(
          new TableRow({
            children: cells
          })
        )
      })

      paragraphNodes.push(
        new Table({
          layout: TableLayoutType.AUTOFIT,
          width: {
            size: 6.27 * 1440,
            type: WidthType.DXA
          },
          rows: tableRowNodes
        })
      )
      return
    }

    recursionDeep(
      Array.from(element.childNodes),
      rootStyles,
      paragraphChildrenNodes
    )

    function recursionDeep(
      childNodes: ChildNode[],
      parentStyles,
      target: any[] = []
    ) {
      childNodes.forEach((node) => {
        const deepAttrs = customMerge(
          customMerge(cssStylesToAttrs(getInlineStyles(node)), parentStyles),
          defaultNodeAttrs
        )

        if (node.nodeType === Node.TEXT_NODE) {
          target.push(
            new TextRun({
              text: node.textContent || '',
              ...deepAttrs
            })
          )
        } else if (node.nodeType === Node.ELEMENT_NODE) {
          const elementNode = node as any
          const tagName = elementNode.tagName.toLocaleLowerCase()

          const elementNodeDeepAttrs = cloneDeep(deepAttrs)

          // 处理图片类型
          if (tagName === 'img') {
            target.push(
              new ImageRun({
                data: elementNode.src,
                transformation: {
                  width: pxToPt(elementNode.width),
                  height: pxToPt(elementNode.height)
                }
              })
            )
            return
          } else if (tagName === 'br') {
            target.push(
              new TextRun({
                text: '',
                ...deepAttrs
              })
            )
          } else if (node.childNodes.length) {
            const tagAttrs = tagsToAttrs([tagName])

            recursionDeep(
              Array.from(elementNode.childNodes),
              customMerge(elementNodeDeepAttrs, tagAttrs),
              target
            )
            return
          }
        }
      })
    }

    const paragraph = new Paragraph({
      children: paragraphChildrenNodes,
      spacing: {
        line: rootStyles.lineSpacing,
        lineRule: 'exact'
      },
      alignment: rootStyles.alignment,
      indent: rootStyles.indent
    })
    paragraphNodes.push(paragraph)
  })

  return paragraphNodes
}

// 自定义合并函数，忽略obj2中的undefined值
function customMerge(target, source) {
  Object.keys(source).forEach((key) => {
    if (Reflect.has(target, key) && target[key] !== undefined) return
    if (source[key] !== undefined) {
      target[key] = source[key]
    }
  })
  return target
}

// function isHeading(tagName: string) {
//   return 'h1,h2,h3,h4,h6'.includes(tagName)
// }

// export function getHeadingLevelByTagName(tagName: string) {
//   switch (tagName.toLocaleLowerCase()) {
//     case 'h1':
//       return HeadingLevel.HEADING_1
//     case 'h2':
//       return HeadingLevel.HEADING_2
//     case 'h3':
//       return HeadingLevel.HEADING_3
//     case 'h4':
//       return HeadingLevel.HEADING_4
//     case 'h5':
//       return HeadingLevel.HEADING_5
//     case 'h6':
//       return HeadingLevel.HEADING_6
//     default:
//       return undefined
//   }
// }
